import psyco
psyco.full()
import cProfile
#import pstats
import os, sys, tempfile, zipfile
import simplejson as json
from PyQt4.QtGui import * 
from PyQt4.QtCore import * 
from commands import *
from sprite import *
from spritefile import *
# ui
from layersdialog import *
from layersdialog2 import *
from spriteeditor import *
from previewwindow import *
from mapeditor import *
from brushlist import *
        
class MainWindowSprite(QMainWindow):
    """ QMainWindow for sprite editor. """
    def __init__(self, sprite):
        QMainWindow.__init__(self, None)

        # Increase the recursion limit so fill method works correctly.
        sys.setrecursionlimit(2000)

        self.sprite = sprite

        self.resize(500, 600)

        self.setWindowTitle(self.tr("Brick Sprite Editor"))

        self.savename = ""
        self.savename_flattened = ""

        self.initialize_menu_bar()
        self.initialize_widgets()
        
        
    def initialize_widgets(self):
        #TODO: This method is a horrible mess.

        self.spl = QGridLayout()
        
        self.frames_container = QWidget()
        self.frames_hbox = QHBoxLayout() 
        self.frames_hbox.setSizeConstraint(QLayout.SetMinAndMaxSize)
        self.frames_hbox.setSpacing(0)
        self.frames_container.setLayout(self.frames_hbox)

        self.sprite_frames_scrollarea = QScrollArea()
        self.sprite_frames_scrollarea.setWidget(self.frames_container)
        
        self.sprite_editor_container = QWidget()
        self.sprite_editor = SpriteEditor(self.sprite, self.frames_hbox, True, None, self.sprite_frames_scrollarea)
        self.sprite_editor_vbox = QVBoxLayout()
        self.sprite_editor_hbox = QHBoxLayout()
        self.sprite_editor_hbox.addWidget(self.sprite_editor, Qt.AlignCenter)
        self.sprite_editor_vbox.addLayout(self.sprite_editor_hbox)
        self.sprite_editor_container.setLayout(self.sprite_editor_vbox)
        
        self.sprite_editor_group = QGroupBox("Sprite Editor")
        self.sprite_editor_scrollarea = QScrollArea()
        self.sprite_editor_scrollarea.setWidget(self.sprite_editor_container)
        self.sprite_editor_scrollarea.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)
        self.sprite_editor_scrollarea.setMinimumSize(400,400)

        self.sprite_editor_scrollarea_vbox = QVBoxLayout()
        self.sprite_editor_scrollarea_vbox.addWidget(self.sprite_editor_scrollarea)
        self.sprite_editor_scrollarea_vbox.setSizeConstraint(QLayout.SetMinAndMaxSize)
        self.sprite_editor_group.setLayout(self.sprite_editor_scrollarea_vbox)

        self.spl.addWidget(self.sprite_editor_group, 0, 0, 1, 2)
        
        """Frames"""

        self.frames_buttonhbox_container = QWidget()
        self.frames_buttonhbox = QHBoxLayout(self.frames_buttonhbox_container)
        self.frames_addbutton = QPushButton("+")
        self.frames_delbutton = QPushButton("-")
        self.frames_buttonhbox.addWidget(self.frames_addbutton)
        self.frames_buttonhbox.addWidget(self.frames_delbutton)
        self.frames_buttonhbox.setAlignment(self.frames_addbutton, Qt.AlignLeft)
        self.frames_buttonhbox.setAlignment(self.frames_delbutton, Qt.AlignLeft)
        self.frames_buttonhbox.insertStretch(2)
        self.frames_buttonhbox.setContentsMargins(0,0,0,0)

        self.connect(self.frames_addbutton, SIGNAL("clicked()"), self.add_frame)
        self.connect(self.frames_delbutton, SIGNAL("clicked()"), self.delete_frame)
        
        self.frames_group = QGroupBox("Frames")
        self.frames_vbox = QVBoxLayout()
        self.frames_vbox.addWidget(self.sprite_frames_scrollarea)
        self.frames_vbox.addWidget(self.frames_buttonhbox_container)
        self.frames_group.setLayout(self.frames_vbox)
        
        self.preview_group = QGroupBox("Preview")
        self.preview_vbox = QVBoxLayout()
        self.preview = PreviewWindow(self.sprite_editor.sprite)
        self.preview_vbox.addWidget(self.preview)
        self.preview_group.setLayout(self.preview_vbox)

        self.spl.addWidget(self.frames_group, 1, 0, 1, 1)
        self.spl.addWidget(self.preview_group, 1, 1, 2, 1)
        
        self.sequencer_group = QGroupBox("Sequencer")
        self.sequencer_vbox = QVBoxLayout()
        self.sequencer_group.setLayout(self.sequencer_vbox)

        self.spl.addWidget(self.sequencer_group, 2, 0, 1, 1)

        main_hbox_container = QWidget()

        main_hbox_container.setLayout(self.spl)
        
        self.setCentralWidget(main_hbox_container)

        self.layers_dialog = LayersDialog2(self.sprite_editor)
        self.color_gradient_list = ColorGradientList(self.sprite_editor)

        self.connect(self.color_gradient_list, SIGNAL("colorchange(QColor)"), self.oncolorchange)
        self.connect(self.sprite_editor, SIGNAL("eyedropper(QColor)"), self.oneyedropper)

        self.sprite_editor.color_gradient_list = self.color_gradient_list

        self.windows = []
        self.windows.append(self.layers_dialog)
        self.windows.append(self.color_gradient_list)

        for window in self.windows:
            window.show()

    """ EVENTS """

    def closeEvent(self, ev):
        #sys.exit()
        self.hide()
        for window in self.windows:
            window.hide()

    def showEvent(self, ev):
        for window in self.windows:
            window.show()

    def resizeEvent(self, ev):
        self.arrange_windows()
        
    def moveEvent(self, ev):
        self.arrange_windows()

    """ Menu Building """

    def arrange_windows(self):
        top = self.geometry().y()

        for window in self.windows:
            window.setGeometry(QRect(self.geometry().x() + self.width(), top, window.width(), window.height()))
            window.raise_()
            # TODO: The 50 here is a foolish hack because I'm not sure how to get the actual bottom of the window (i.e. including border).
            top = window.geometry().bottom() + 50


    def add_menu(self, menu_name, actions, menu = None):
        if not menu:
            menu = self.menuBar().addMenu(self.tr(menu_name))

        for action in actions:
            if action[0] != "SEPARATOR":
                qa = QAction(self.tr(action[0]), self)
                qa.setShortcut(self.tr(action[1]))
                if action[2]:
                    qa.setStatusTip(self.tr(action[2]))
                self.connect(qa, SIGNAL("triggered()"), action[3])
                qa.setEnabled(action[4])
                menu.addAction(qa)
            else:
                menu.addSeparator()
        return menu

    def add_submenu(self, menu_name, actions, menu):
        menu = menu.addMenu(self.tr(menu_name))
        self.add_menu(self.tr(menu_name), actions, menu)

    def initialize_menu_bar(self):
        # File Menu
        file_actions = ( 
                ("&New", "Ctrl+N", "New sprite.", self.new_sprite, True),
                ("&Open", "Ctrl+O", "Open.", self.load, True),
                ("SEPARATOR",None,None,None, True),
                ("&Save", "Ctrl+S", "Save sprite.", self.save, True),
                ("Save As...", None, "Save sprite as...", self.saveas, True),
                ("Save As Animated GIF...", None, "Save sprite as Animated GIF...", self.saveas_gif, True),
                ("Save For Brick", None, "Save for Brick...", self.save_for_brick, True),
                ("SEPARATOR",None,None,None, True),
                ("Close Window", "Ctrl+W", "Close", self.close, True),
                )

        self.add_menu("&File", file_actions)

        flip_actions = (
                ("Flip Sprite Horizontally", None, "Flip Sprite Horizontally.", self.flip_sprite_horizontally,True),
                ("Flip Frame Horizontally", None, "Flip Frame Horizontally.", self.flip_frame_horizontally,True),
                ("Flip Layer Horizontally", None, "Flip Layer Horizontally.", self.flip_layer_horizontally,True),
                ("Flip Sprite Vertically", None, "Flip Sprite Vertically.", self.flip_sprite_vertically,True),
                ("Flip Frame Vertically", None, "Flip Frame Vertically.", self.flip_frame_vertically,True),
                ("Flip Layer Vertically", None, "Flip Layer Vertically.", self.flip_layer_vertically,True),
                )


        edit_actions = (
                ("Undo", "Ctrl+Z", "Undo last action.", self.undo, True),
                ("Redo", "Ctrl+Y", "Redo last action.", self.redo, True),
                ("SEPARATOR",None,None,None, True),
                ("Cut", "Ctrl+X", "Cut.", self.cut_selection, True),
                ("Copy", "Ctrl+C", "Copy.", self.copy_selection, True),
                ("Paste", "Ctrl+V", "Paste.", self.paste_selection, True),
                ("SEPARATOR",None,None,None, True),
                ("Add Blank Frame", None, "Add blank frame.", self.add_frame, True),
                ("Duplicate Frame", "Ctrl+T", "Duplicate frame.", self.duplicate_frame, True),
                ("Delete Frame", None, "Duplicate frame.", self.duplicate_frame, True),
                ("Select All", "Ctrl+A", "Select All.", self.select_all, True),
                ("Clear Selection", "Ctrl+D", "Clear selection.", self.clear_selection, True),
                ("SEPARATOR",None,None,None,True),
                ("Crop", None, "Crop.", self.not_implemented,False),
                ("Copy Layer to All Frames", None, "Copy layer to all frames.", self.not_implemented,False),
                ("SEPARATOR",None,None,None,True),
                ("Nudge left", "Left", "Nudge left.", self.nudge_left,True),
                ("Nudge right", "Right", "Nudge right.", self.nudge_right,True),
                ("Nudge up", "Up", "Nudge up.", self.nudge_up,True),
                ("Nudge down", "Down", "Nudge down.", self.nudge_down,True),
                ("SEPARATOR",None,None,None,True),
                ("Move left 1 Color", "Ctrl+Left", "Move left 1 color.", self.left_color,True),
                ("Move right 1 color", "Ctrl+Right", "Move right 1 color.", self.right_color,True),
                ("SEPARATOR",None,None,None,True),
                ("Hue Shift Left", "Ctrl+1", "Hue shift left.", self.hue_shift_left,True),
                ("Hue Shift Right", "Ctrl+2", "Hue shift right.", self.hue_shift_right,True),
                ("Decrease Saturation", "Ctrl+3", "Saturation shift left.", self.saturation_decrease,True),
                ("Increase Saturation", "Ctrl+4", "Saturation shift right.", self.saturation_increase,True),
                ("Decrease Value", "Ctrl+5", "Saturation shift left.", self.value_decrease,True),
                ("Increase Value", "Ctrl+6", "Saturation shift right.", self.value_increase,True),
                ("SEPARATOR",None,None,None,True),
                )

        selection_flip_actions = (
                ("Flip Selection Horizontally", None, "Flip Selection Horizontally.", self.flip_selection_horizontally,True),
                ("Flip Selection Vertically", None, "Flip Selection Horizontally.", self.flip_selection_vertically,True),
                )

        selection_actions = (
                ("Deselect", "Ctrl+D", "Clear selection.", self.clear_selection, True),
                )

        edit_menu = self.add_menu("&Edit", edit_actions)

        self.add_submenu("F&lip", flip_actions, edit_menu)

        selection_menu = self.add_menu("&Selection", selection_actions)

        self.add_submenu("F&lip", selection_flip_actions, selection_menu)

        view_actions = (
                ("Zoom In", "Ctrl+=", "Zoom In.", self.zoom_in,True),
                ("Zoom Out", "Ctrl+-", "Zoom Out.", self.zoom_out,True),
                ("Toggle Tiled View", "Ctrl+I", "Toggle Tiled View.", self.toggle_tiled_view,True),
                )

        view_menu = self.add_menu("&View", view_actions)

    """ Menu Handlers """

    def not_implemented(self):
        pass

    """ Menu Handlers: Editing """

    def flip_sprite_horizontally(self):
        self.sprite_editor.flip("sprite", True, False)

    def flip_frame_horizontally(self):
        self.sprite_editor.flip("frame", True, False)

    def flip_layer_horizontally(self):
        self.sprite_editor.flip("layer", True, False)

    def flip_sprite_vertically(self):
        self.sprite_editor.flip("sprite", False, True)

    def flip_frame_vertically(self):
        self.sprite_editor.flip("frame", False, True)

    def flip_layer_vertically(self):
        self.sprite_editor.flip("layer", False, True)

    def left_color(self):
        self.sprite_editor.left_color()

    def right_color(self):
        self.sprite_editor.right_color()

    def nudge_left(self):
        self.sprite_editor.nudge(QPoint(-1,0))

    def nudge_right(self):
        self.sprite_editor.nudge(QPoint(1,0))

    def nudge_up(self):
        self.sprite_editor.nudge(QPoint(0,-1))

    def nudge_down(self):
        self.sprite_editor.nudge(QPoint(0,1))

    def hue_shift_left(self):
        self.sprite_editor.hsv_offset(-5,0,0)

    def hue_shift_right(self):
        self.sprite_editor.hsv_offset(5,0,0)

    def saturation_decrease(self):
        self.sprite_editor.hsv_offset(0,-4,0)

    def saturation_increase(self):
        self.sprite_editor.hsv_offset(0,4,0)

    def value_decrease(self):
        self.sprite_editor.hsv_offset(0,0,-4)

    def value_increase(self):
        self.sprite_editor.hsv_offset(0,0,4)

    """ Color Swap """
    def color_swap(self):
        self.sprite_editor.color_swap()

    """ Menu Handlers: Selection """

    def select_all(self):
        self.sprite_editor.selection.select_all()

    def clear_selection(self):
        self.sprite_editor.clear_selection()

    def cut_selection(self):
        self.sprite_editor.selection.cut()

    def copy_selection(self):
        self.sprite_editor.selection.copy()

    def paste_selection(self):
        self.sprite_editor.selection.paste()

    def flip_selection_horizontally(self):
        self.sprite_editor.flip("selection", True, False)

    def flip_selection_vertically(self):
        self.sprite_editor.flip("selection", False, True)

    """ Menu Handlers: Frame """

    def add_frame(self):
        """Add a new frame."""
        self.sprite_editor.add_frame()
        
    def duplicate_frame(self):
        """Duplicate currently selected frame."""
        new_index = self.sprite_editor.duplicate_frame()
        # TODO: Scroll to the new frame.
        self.sprite_editor.scrollarea.ensureWidgetVisible(self.sprite_editor.frame_canvases[new_index])
        
    
    def delete_frame(self):
        """Remove currently selected frame."""
        self.sprite_editor.delete_frame()

    """ Menu Handlers: Undo & Redo """
        
    def redo(self):
        """Redo the last undone command."""
        self.sprite_editor.redo()
    
    def undo(self):
        """Undo the previous command."""
        self.sprite_editor.undo()

    """ Menu Handlers: File IO """

    def close(self):
        self.hide()

        for window in self.windows:
            window.hide()
    
    def new_sprite(self):
        pass

    def saveas(self):
        """Save a Brick Sprite file, first prompting for filename."""
        self.savename = QFileDialog.getSaveFileName(self, "Save Sprite As...")

        if self.savename:
            sf = SpriteFile(self.sprite_editor.sprite)
            sf.save(self.savename)

            self.update_title(os.path.basename(str(self.savename)))
        
    def saveas_gif(self):
        """Save a Brick Sprite file, first prompting for filename."""
        self.savename = QFileDialog.getSaveFileName(self, "Save Sprite As...")

        if self.savename:
            sf = SpriteFile(self.sprite_editor.sprite)
            sf.save_gif(self.savename)

            self.update_title(os.path.basename(str(self.savename)))

    def save(self):
        """Save a Brick Sprite file, if a self.savename exists don't prompt for new filename."""
        if len(self.savename) == 0:
	        self.savename = QFileDialog.getSaveFileName(self, "Save Sprite")
            
        if self.savename:
            sf = SpriteFile(self.sprite_editor.sprite)
            sf.save(self.savename)

            self.update_title(os.path.basename(str(self.savename)))
        

    def save_for_brick(self):
        """Save a flattened image."""
        if len(self.savename_flattened) == 0:
	        self.savename_flattened = QFileDialog.getSaveFileName(self, "Save Sprite For Brick")
            
        if self.savename_flattened:
	        sf = SpriteFile(self.sprite_editor.sprite)
	        sf.save(self.savename_flattened, True)

    def load(self):
        """Load a Brick Sprite file."""
        # TODO: Confirm dialog.
        self.loadname = QFileDialog.getOpenFileName(self, "Load Sprite")
        if self.loadname:
            sf = SpriteFile(None)
            self.sprite_editor.set_sprite(sf.load(self.loadname))
            self.preview.animation.set_sprite(self.sprite_editor.sprite)
            self.layers_dialog.initialize_list()
            self.savename = self.loadname
            self.update_title(os.path.basename(str(self.savename)))
        
    """ View """
    def zoom_in(self):
        """Increase zoomlevel by 1."""
        self.sprite_editor.zoom_in()

    def zoom_out(self):
        """Decrease zoomlevel by 1."""
        self.sprite_editor.zoom_out()

    def toggle_tiled_view(self):
        """Toggle tiled view."""
        self.sprite_editor.toggle_tiled_view()

    """ Misc """

    def update_title(self, title):
        self.setWindowTitle(self.tr("Brick Sprite Editor: %s" % title))

    def oncolorchange(self, color):
        self.sprite_editor.color_picker.set_color(color)

    def oneyedropper(self, color):
        self.color_gradient_list.set_color(color)
        
def go():
    app = QApplication(sys.argv)
    map_editor = MapEditor(2048,1152) # 16:9
    map_editor.show()
    map_editor.raise_()
    sys.exit(app.exec_())

if __name__ == "__main__":
	go()
